package example.documentbased.mainModule.services.delegates
{
	import example.documentbased.mainModule.models.doman.Document;
	import example.documentbased.mainModule.models.doman.Editor;
	import example.documentbased.mainModule.models.factories.ItemsFactory;
	import example.documentbased.mainModule.models.mappers.DocumentMapper;
	import example.documentbased.mainModule.models.mappers.EditorMapper;
	import example.documentbased.mainModule.models.vo.DocumentVO;
	import example.documentbased.mainModule.models.vo.EditorVO;
	import example.documentbased.mainModule.services.IDocumentService;
	import example.documentbased.mainModule.services.IEditorService;
	
	import mx.collections.ArrayList;
	
	import raix.interactive.AbsEnumerable;
	import raix.reactive.IObservable;
	import raix.reactive.Observable;
	import raix.reactive.Observer;
	import raix.reactive.Unit;

	public class MainServiceDelegate implements IMainServiceDelegate
	{
		// Mapping from domain to VOs and creating necessary data structures.
		private var _documentService:IDocumentService;
		private var _editorService:IEditorService;
		private var _editorMapper:EditorMapper;
		private var _documentMapper:DocumentMapper;
		
		public function MainServiceDelegate(editorService:IEditorService, 
											documentService:IDocumentService, 
											editorMapper:EditorMapper, 
											documentMapper:DocumentMapper)
		{
			super();
			
			_editorService = editorService;
			_documentService = documentService;
			_editorMapper = editorMapper;
			_documentMapper = documentMapper;
		}
		
		public function getEditorsWithDocuments():IObservable
		{
			return Observable.defer(function():IObservable 
			{ 
				return _editorService.getEditors()
				.mapMany(function(editors:Vector.<Editor>):IObservable
				{
					const editorsArray:Array = _editorMapper.fromDomainItems(editors);
					
					return Observable.fromArray(editorsArray)
					.mapMany(function(editorVO:EditorVO):IObservable
					{
						return _documentService.getDocuments(editorVO.id)
						.mapMany(function(documents:Vector.<Document>):IObservable
						{
							editorVO.documents = new ArrayList(_documentMapper.fromDomainItems(documents));
							
							return Observable.value(new Unit());
						});
					}).takeLast(1)
					.mapMany(function():IObservable{ return Observable.value(new ArrayList(editorsArray)); });
				})
			});
		}
		
		public function getEditorWithDocuments(editorId:String):IObservable
		{
			return Observable.defer(function():IObservable 
			{
				return _editorService.getEditor(editorId)
				.mapMany(function(editor:Editor):IObservable
				{
					var editorVO:EditorVO = _editorMapper.fromDomain(editor);
					
					return _documentService.getDocuments(editor.id)
					.mapMany(function(documents:Vector.<Document>):IObservable
					{
						editorVO.documents = new ArrayList(_documentMapper.fromDomainItems(documents));
						
						return Observable.value(editorVO);
					});
				});
			});
		}
		
		public function saveDocument(document:DocumentVO):IObservable
		{
			return Observable.defer(function():IObservable 
			{
				return _documentService.saveDocument(_documentMapper.toDomain(document))
				.mapMany(function(id:String):IObservable
				{
					return Observable.value(id);
				});
			})
		}
		
		public function saveEditor(editor:EditorVO):IObservable
		{
			return Observable.defer(function():IObservable 
			{
				return _editorService.saveEditor(_editorMapper.toDomain(editor))
				.mapMany(function(id:String):IObservable
				{
					return Observable.value(id);
				});
			})
		}
	}
}